package com.sulent.frame.file.impl;

import com.sulent.frame.file.FileServer;
import com.sulent.frame.file.dto.FileVo;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName FtpFileServer
 * @Description: 基于Apache-commons-net 实现处理FTP服务系列操作
 * @Author Submerge.
 * @Since 2024/1/18 10:25
 * @Version 1.0
 */
@Data
public class FTPFileServer implements FileServer {

    private String host;
    private String username;
    private int port;
    private String password;
    private String encoding;

    public FTPFileServer(String host, int port, String username, String password, String encoding) {
        this.port = port;
        this.host = host;
        this.username = username;
        this.password = password;
        this.encoding = encoding;
    }

    @Override
    public void uploadFile(File file, String targetPath) {
        // FTP上传文件的实现


    }

    @Override
    public File downloadFile(String sourceFilePath, String destinationPath) {
        // FTP下载文件的实现
        FTPClient ftpClient = connectFtpServer(host, port, username, password, encoding);
        if (!ftpClient.isConnected() || !ftpClient.isAvailable()){
            throw new RuntimeException("FTP 连接无效，请检查网络或连接配置！");
        }
        ftpClient.enterLocalPassiveMode();//被动模式
        File file = new File(destinationPath);
        if (!file.exists()){
            file.mkdirs();
        }
        ftpClient.enterLocalPassiveMode();
        String fileName = sourceFilePath.substring(sourceFilePath.lastIndexOf("/")+1);
        FileOutputStream local = null;
        try {
            local = new FileOutputStream(new File(file,fileName));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        try {
            boolean result = ftpClient.retrieveFile(sourceFilePath, local);
            if (!result){
                throw new RuntimeException("文件下载失败！");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //关流，断开连接，
            try {
                if (local!=null){
                    local.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            closeFTPConnect(ftpClient);
        /*
            断开后测试成功断开
            System.out.println("FTP 连接是否成功：" + ftpClient.isConnected());
            System.out.println("FTP 连接是否有效：" + ftpClient.isAvailable());*/
        }
        return null;
    }

    @Override
    public List<FileVo> listFiles(String targetPath) {
        //1.登录连接
        FTPClient ftpClient = null;
        List<FileVo> fileVos = null;
        try {
            ftpClient = connectFtpServer(host, port, username, password, encoding);
            ftpClient.enterLocalPassiveMode();
            FTPFile[] ftpFiles;
            //2.列出文件目录
            if (StringUtils.isNotBlank(targetPath)) {
                ftpClient.changeWorkingDirectory(targetPath);
                ftpFiles = ftpClient.listFiles(targetPath);
            } else {
                ftpFiles = ftpClient.listFiles();
            }
            fileVos = new ArrayList<>();
            for (FTPFile ftpFile : ftpFiles) {
                FileVo fileVo = new FileVo();
                fileVo.setName(ftpFile.getName());
                fileVo.setType(ftpFile.getType()==1?"DIRECTORY":"FILE");
                fileVo.setSize(ftpFile.getSize());
                fileVos.add(fileVo);
            }

            //3.退出关闭连接
        } catch (IOException e) {
            throw new RuntimeException("FTP服务连接失败，请检查连接参数是否正确或网络是否通畅");
        } finally {
            //3.退出关闭连接
            closeFTPConnect(ftpClient);
        }
        return fileVos;
    }

    /**
     * 连接 FTP 服务器
     *
     * @param addr     FTP 服务器 IP 地址
     * @param port     FTP 服务器端口号
     * @param username 登录用户名
     * @param password 登录密码
     * @return
     * @throws Exception
     */
    private FTPClient connectFtpServer(String addr, int port, String username, String password, String controlEncoding) {
        FTPClient ftpClient = new FTPClient();
        try {
            /**设置文件传输的编码*/
            ftpClient.setControlEncoding(controlEncoding);

            /**连接 FTP 服务器
             * 如果连接失败，则此时抛出异常，如ftp服务器服务关闭时，抛出异常：
             * java.net.ConnectException: Connection refused: connect*/
            ftpClient.connect(addr, port);
            /**登录 FTP 服务器
             * 1）如果传入的账号为空，则使用匿名登录，此时账号使用 "Anonymous"，密码为空即可*/
            if (StringUtils.isBlank(username)) {
                ftpClient.login("Anonymous", "");
            } else {
                ftpClient.login(username, password);
            }

            /** 设置传输的文件类型
             * BINARY_FILE_TYPE：二进制文件类型
             * ASCII_FILE_TYPE：ASCII传输方式，这是默认的方式
             * ....
             */
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);


            /**
             * 确认应答状态码是否正确完成响应
             * 凡是 2开头的 isPositiveCompletion 都会返回 true，因为它底层判断是：
             * return (reply >= 200 && reply < 300);
             */
            int reply = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                /**
                 * 如果 FTP 服务器响应错误 中断传输、断开连接
                 * abort：中断文件正在进行的文件传输，成功时返回 true,否则返回 false
                 * disconnect：断开与服务器的连接，并恢复默认参数值
                 */
                ftpClient.abort();
                ftpClient.disconnect();
            } else {
                System.out.println("FTP连接成功！");
            }
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println(">>>>>FTP服务器连接登录失败，请检查连接参数是否正确，或者网络是否通畅*********");
        }
        return ftpClient;
    }

    /**
     * 使用完毕，应该及时关闭连接
     * 终止 ftp 传输
     * 断开 ftp 连接
     *
     * @param ftpClient
     * @return
     */
    private void closeFTPConnect(FTPClient ftpClient) {
        try {
            if (ftpClient != null && ftpClient.isConnected()) {
                ftpClient.abort();
                ftpClient.disconnect();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        FTPFileServer fileServer = new FTPFileServer("172.16.48.16",21,"dgftp","Gd@123456","utf-8");
        String filePath = "/datavdb/ftp/data/csv/aa/abc_20240110110524.csv";
        fileServer.listFiles("/datavdb/ftp/data/csv/aa");
        fileServer.downloadFile(filePath,"temp-file");
    }


    @Override
    public void close() throws Exception {
        System.out.println("ftp sever close");
    }
}
